<template>
    <el-form ref="xklFormText" :model="form" :label-width="labelWidth()" v-bind="form.element" v-loading="form.loading">
        <el-row>
            <el-col v-for="item in renderFormOptions" :span="item.span || opts.span" :key="item.prop">
                <el-form-item :label="item.label + '：'" :label-width="labelWidth(item)">
                    <slot v-if="!!slots[item.prop]" :name="item.prop"></slot>
                    <span v-else-if="item.reflect">{{ form[item.reflect] }}</span>
                    <component v-else :is="'XklText' + ComponentMapping[item.type]" :form="form" :option="item"
                        v-on="item.events">
                    </component>
                </el-form-item>
            </el-col>
        </el-row>
    </el-form>
</template>
<script setup lang="ts">
import { upperLeadCase } from '~/utils'
import { TextFormOption } from '~/utils/types';
import { FormInstance } from 'element-plus'
import { computed, ref, useSlots } from 'vue';
import { Component, ComponentMapping } from '~/utils/enums';
defineOptions({ name: 'XklTextForm' })
const props = defineProps(['form'])
const slots = useSlots()

const { form } = props
const xklForm = ref<FormInstance>()

const opts = form.opts

const labelWidth = computed(() => {
    const docEl = document.documentElement
    const width = docEl.getBoundingClientRect().width;
    const rem = width / 10;
    return (item?) => {
        if (item && item.labelWidth) {
            return ((item.labelWidth / rem) * (rem / 192)) + 'rem'
        }
        return ((opts.labelWidth / rem) * (rem / 192)) + 'rem'
    }
})

const formKeys = Object.keys(form)

const formOptions: TextFormOption[] = []
formKeys.map(key => {
    if (!form['get' + upperLeadCase(key)]) {
        return
    }

    const option: TextFormOption = form['get' + upperLeadCase(key)]()
    if (!option) {
        console.error(`未找到${key}的可匹配getter`)
        return
    }



    const placeholderPrefix = [Component.Select, Component.DictSelect, Component.UrlSelect, Component.TreeSelect].includes(option.type) ? '请选择' : '请输入'
    const placeholder = option.element?.placeholder || `${placeholderPrefix}${option.label}`

    option.prop = key


    const field: TextFormOption = {
        ...option,
        element: {
            placeholder: placeholder,
            ...option.element
        },
        events: option.events || {}
    }


    if (opts.mode) {
        if (option.mode && option.mode.includes(opts.mode)) {
            formOptions.push(field)
        }
    } else {
        formOptions.push(field)
    }

})

const renderFormOptions = computed(() => {
    if (xklForm.value) {
        xklForm.value.clearValidate()
    }



    return formOptions.filter(item => {
        if (item.required !== undefined) {
            if (opts.mode && opts.mode.toLowerCase().includes('query')) {
                if (item.rules) {
                    item.rules = item.rules.filter(rule => !rule.required)
                }
            } else {
                const getRequired = typeof item.required === 'boolean' ? () => item.required : item.required
                const triggers = [0, 1, 6].includes(item.type) ? ['blur'] : ['change']
                if (getRequired()) {
                    if (item.rules) {
                        item.rules = [{ required: true, message: item.element?.placeholder, trigger: triggers }, ...item.rules]
                    } else {
                        item.rules = [{ required: true, message: item.element?.placeholder, trigger: triggers }]
                    }
                } else {
                    if (item.rules) {
                        item.rules = item.rules.filter(rule => !rule.required)
                    }
                }
            }
        }


        let show = true
        if (typeof item.show === 'function') {
            show = item.show()
        } else if (typeof item.show === 'boolean') {
            show = item.show
        }
        return show
    })
})




form.getBindingValue = (filter?: string[], type?: 'include' | 'exclude') => {
    const bindForm: any = {}
    if (filter) {
        if (!Array.isArray(filter)) {
            return bindForm
        }
        formOptions.forEach(field => {
            const isInclude = filter.includes(field.prop)
            if (type === 'exclude' ? !isInclude : isInclude) {
                bindForm[field.prop] = form[field.prop]
            }
        })
    } else {
        formOptions.forEach(field => {
            bindForm[field.prop] = form[field.prop]
        })
    }
    return bindForm
}

let enableSubmit = true
form.submit = (callback) => {
    if (!enableSubmit) {
        return
    }
    enableSubmit = false
    xklForm.value?.validate((valid: boolean) => {
        if (valid) {
            callback(() => {
                setTimeout(() => {
                    enableSubmit = true
                }, 300)
            })
        } else {
            enableSubmit = true
        }
    })
}

form.getRef = () => {
    return xklForm.value
}

form.getLabel = (key: string) => {
    if (form._label) {
        form._label[key]
    }
    return ''
}

</script>

<style lang="scss" scoped>
.action-col {
    display: flex;
    justify-content: flex-end;
}
</style>